package de.koller.worlders.engine.tiles.light;

import de.koller.oceanFramework.util.ColorIntUtil;
import de.koller.worlders.WSea;
import de.koller.worlders.engine.tiles.Tile;
import de.koller.worlders.engine.tiles.data.TileBuffer;
import de.koller.worlders.engine.util.thread.IResource;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;

public class LightContainer extends WSea implements IResource {

	public static int DIS = (int)(0xff / LightUtil.LIGHT_DISPOSE);
	private int[][] lightMap = null;
	//private Tile[][] tilebuffer = null;
	private TileBuffer tileBuffer;
	private int ax, ay, bx, by;
	
	private final Set<LightSource> sources = new HashSet<>();
	private final Set<LightSource> addedSources = new HashSet<>();
	private final Set<LightSource> deletedSources = new HashSet<>();
	
	private final LinkedList<int[]> queue = new LinkedList<>();
	private boolean rdy = true;
	
	public LightContainer() {

	}
	
	synchronized public LightSource addLightSource( int x, int y, int light ) {
		LightSource l = new LightSource( x, y, light );
		addedSources.add( l );
		return l;
	}

	synchronized public void removeLightSource( LightSource source ) {
//		sources[source.x][source.y].remove( source );
		deletedSources.add( source );
	}

	public int getLight( int x, int y ) {
		try {
			if( lightMap == null )
				return 0xff000000;
			return lightMap[x-ax][y-ay];
		} catch( ArrayIndexOutOfBoundsException ex ) {
			return 0xff000000;
		}
	}
	
	private float getMultiplyForLight( int x, int y ) {
//		Tile t = wroot.getTileMap().getTileAtPos( x+.5f, y+.5f );
//		Tile t = tilebuffer[x-ax][y-ay];
		Tile t = tileBuffer.getTile( x, y ).getTile();
		if( t == null ) return 1;
		return t.getLightTranslucents();
	}

	public void clearBuffer( int sx, int sy, int sw, int sh ) {
		ax = sx - DIS; //if( ax < 0 ) ax = 0;
		ay = sy - DIS; //if( ay < 0 ) ay = 0;
		bx = sx+sw+DIS; //if( bx > MapData.MAP_SIZE ) bx = MapData.MAP_SIZE;
		by = sy+sh+DIS; //if( by > MapData.MAP_SIZE ) by = MapData.MAP_SIZE;
		
		if( lightMap == null ) {
			lightMap = new int[ bx-ax ][ by-ay ];
			tileBuffer = new TileBuffer( bx-ax, by-ay, wroot.getTileMap().tileHolder );
		}
		
		assert bx-ax == lightMap.length;
		assert by-ay == lightMap[0].length;
	}

	@Override
	public void calculateResource() {
		rdy = false;
		
		if( lightMap == null ) {
			rdy = true;
			return;
		}
		
		synchronized( this ) {
			sources.addAll( addedSources );
			sources.removeAll( deletedSources );
			
			addedSources.clear();
			deletedSources.clear();
		}

		if( wroot == null ) {
			rdy = true;
			return;
		}
		
//		EnvRoot er = wroot.environment;
//		for( int x = ax; x < bx; x++ )
//			for( int y = ay; y < by; y++ ) 
//				lightMap[x][y] = er.getOutdoor()[x][y] == OutdoorType.Outdoor ? er.getDaylight() : 0xff000000;
		
		tileBuffer.swapBuffer( ax, ay );
		for( int x = 0; x < lightMap.length; x++ )
			for( int y = 0; y < lightMap[0].length; y++ ) {
				lightMap[x][y] = 0xff000000;
//				tilebuffer[x][y] = wroot.getTileMap().serchTile( x+ax, y+ay );
			}
		
		for( LightSource l : sources )
			addLight( l.x, l.y, l.light );
		
		for( int x = 0; x < lightMap.length; x++ )
			for( int y = 0; y < lightMap[0].length; y++ )
				lightMap[x][y] = LightUtil.mergeMax( lightMap[x][y], tileBuffer.getTile( x+ax, y+ay ).getTile().getDrawLight() );
		
		rdy = true;
	}

	public boolean isRdy() {
		return rdy;
	}
	
	private void addLight( int x, int y, int light ) {
		if( x < ax || y < ay || x >= bx || y >= by )
			return;
		//System.out.println( x + " " + ax + " " + bx + " " + y + " " + ay + " " + by );
		if( !LightUtil.isMeBrighter( light, lightMap[x-ax][y-ay] ) )
			if( !( light == lightMap[x-ax][y-ay] ) )
				return;
		
		lightMap[x-ax][y-ay] = LightUtil.mergeMax( light, lightMap[x-ax][y-ay] );
		for( Iterator<int[]> i = new NeighborIterator(); i.hasNext(); ) {
			int[] z = i.next();
			queue.addLast( new int[] { x+z[0], y+z[1] } );
		}
		while( !queue.isEmpty() ) {
			int[] z = queue.removeFirst();
			this.addLight( z[0], z[1] );
		}
	}
	
	private void addLight( int x, int y ) {
		if( x >= bx || x < ax || y >= by || y < ay )
			return;
		
		int m = 0xff000000;
			
		for( Iterator<int[]> i = new NeighborIterator(); i.hasNext(); ) {
			int[] z = i.next();
			try { 
				m = LightUtil.mergeMax( m, lightMap[ z[0]+x-ax ][ z[1]+y-ay ] );
			} catch( ArrayIndexOutOfBoundsException ex ) {}
		}

		m = LightUtil.subLight( m, getMultiplyForLight( x, y ) );

		int r = ColorIntUtil.getRValue( m );
		int g = ColorIntUtil.getGValue( m );
		int b = ColorIntUtil.getBValue( m );
		if( r+g+b <= 0 )
			return;

		if( LightUtil.isMeBrighter( m, lightMap[x-ax][y-ay] ) ) {
			lightMap[x-ax][y-ay] = LightUtil.mergeMax( m, lightMap[x-ax][y-ay] );
			for( Iterator<int[]> i = new NeighborIterator(); i.hasNext(); ) {
				int[] z = i.next();
				queue.addLast( new int[] { x+z[0], y+z[1] } );
			}
		}
	}
	
	public int getLightSourcesNumber() {
		return sources.size();
	}

	public int getAx() {
		return ax;
	}

	public int getAy() {
		return ay;
	}

	public int getBx() {
		return bx;
	}

	public int getBy() {
		return by;
	}
	
}
